/* 
 * ipmsg client
 * using UNIX domain socket with SOCK_SEQPACKET protocol to communicate with the ipmsg server.
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <pthread.h>
#include "public.h"

static int sockfd;

static int Read(int sockfd);
static char *get_env_user(void);
static void *thread_fun(void *arg);

static void do_interrupt(int sig)
{
	rl_delete_text(0, rl_point);
	write(1, "\n", 1);
	rl_point = 0;
	rl_forced_update_display();
}

int main(int argc, char *argv[])
{
	struct sockaddr_un serv;
	char *login_name = NULL;
	char buffer[PACKET_LEN_MAX];
	char *line = NULL;
	struct sigaction sigact;
	char *passwd = NULL;
	pthread_t tid;
	int err;

	sigact.sa_handler = do_interrupt;
	sigemptyset(&sigact.sa_mask);
	sigact.sa_flags = 0;
	sigaction(SIGINT, &sigact, NULL);

	sockfd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
	if (sockfd < 0) {
		perror("socket");
		goto end;
	}
	bzero(&serv, sizeof serv);
	serv.sun_family = AF_UNIX;
	strcpy(serv.sun_path, UNIX_PATH);
	if (connect(sockfd, (struct sockaddr *)&serv, sizeof serv) < 0) {
		perror("connect");
		goto end;
	}
	passwd = getpass("password:");
	login_name = get_env_user();
	if (!login_name) {
		fprintf(stderr, "There is no login name\n");
		goto end;
	}
	memset(buffer, 0, sizeof buffer);
	snprintf(buffer, sizeof buffer - 1, "%s %s %d %d %s\n", LOGIN, 
			login_name, getuid(), getgid(), passwd);
	if (write(sockfd, buffer, strlen(buffer)) < 0) {
		fprintf(stderr, "Login failed!\n");
		goto end;
	}
	if ((err = pthread_create(&tid, NULL, thread_fun, NULL)) != 0) {
		strerror_r(err, buffer, sizeof buffer);
		fprintf(stderr, "pthread_create: %s\n", buffer);
		goto end;
	}

	while (1) {
		if (line)
			break;
		line = readline("(ipmsg)");
		if (!line || !strcmp(line, EXIT)) {
			goto end;
		}
		if (strlen(line) == 0)
			continue;
		add_history(line);
		
		if (write(sockfd, line, strlen(line)) < 0) {
			perror("write");
			fprintf(stderr, "execute command failed\n");
			continue;
		}
	}
end:
	return 0;
}

static void *thread_fun(void *arg)
{
	while (1) {
		if (Read(sockfd) < 0)
			perror("read");
	}
	return NULL;
}

static char *get_env_user(void)
{
	char *login_name = NULL;

	login_name = getenv("LOGNAME");
	if (!login_name) {
		login_name = getenv("USERNAME");
		if (!login_name) {
			login_name = getenv("USER");
		}
	}
	return login_name;
}

/* 
 * this function should display the result from the server and correspond to the
 * terminal 
 */
static int Read(int sockfd)
{
	char buffer[PACKET_LEN_MAX];
	int ret = -1;

	while (1) {
		memset(buffer, 0, sizeof buffer);
		if (read(sockfd, buffer, sizeof buffer) < 0) {
			break;
		}
		else {
			fprintf(stdout, "%s", buffer);
			if (strchr(buffer, '\n')) {
				ret = 0;
				break;
			}
		}
	}
	return ret;
}
